﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using SimpleExpression;
using System.Xml.Serialization;

namespace SimpleExpression
{
    [XmlInclude(typeof(ConditionExpression))]
    public class FilterExpression : Expression
    {
        private ExpressionCollection conditions;
        private LogicalOperator logicalOperator;
        private EntityMetadata entityMetadata;

        public FilterExpression()
            :this(LogicalOperator.And)
        {
            
        }

        public FilterExpression(LogicalOperator logicalOperator)
        {
            this.logicalOperator = logicalOperator;
            this.conditions = new ExpressionCollection();
        }

        public FilterExpression(EntityMetadata entityMetadata)
            : this()
        {
            this.entityMetadata = entityMetadata;
        }

        public void Add(string property, ConditionOperator conditionOperator, object value)
        {
            this.Add(GetAttributeExpression(property), conditionOperator, value);
        }

        public void Add(object value1, ConditionOperator conditionOperator, object value2)
        {
            this.Add(value1, conditionOperator, value2, LogicalOperator.And);
        }

        public void Add(string property, ConditionOperator conditionOperator, object value2, LogicalOperator logicalOperator)
        {
            this.Add(GetAttributeExpression(property), conditionOperator, value2, logicalOperator);
        }

        public void Add(object value1, ConditionOperator conditionOperator, object value2, LogicalOperator logicalOperator)
        {
            this.Add(new ConditionExpression(logicalOperator, value1, conditionOperator, value2));
        }

        public void Add(Expression expression)
        {
            this.conditions.Add(expression);
        }

        public ExpressionCollection Conditions
        {
            get { return this.conditions; }
            set { this.conditions = value; }
        }

        public LogicalOperator LogicalOperator
        {
            get { return this.logicalOperator; }
        }

        public EntityMetadata EntityMetadata
        {
            get { return this.entityMetadata; }
            set { this.entityMetadata = value; }
        }

        #region Expression

        public override void Accept(ExpressionVisitor visitor)
        {
            visitor.Visit(this);
        }

        #endregion

        private AttributeExpression GetAttributeExpression(string name)
        {
            // Si se encuentra el physicalName entonces se agrega un AttributeExpression de lo contrario un ViewAttributeExpression
            switch (this.EntityMetadata.Properties.Contains(name))
            {
                case MappingType.None:
                    break;
                case MappingType.Physical:
                    return new AttributeExpression(this.EntityMetadata[name]);
                case MappingType.Platform:
                    return new ViewAttributeExpression(this.EntityMetadata.Properties[name, MappingType.Platform]);
                default:
                    break;
            }

            throw new NotImplementedException();
        }
    }
}
